package com.ruoyi.labdata.service.impl;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.labdata.domain.LabTwoDimensionalCode;
import com.ruoyi.labdata.mapper.LabTwoDimensionalCodeMapper;
import com.ruoyi.labdata.service.ILabTwoDimensionalCodeService;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;

/**
 * 二维码Service业务层处理
 *
 * @author lzlong
 * @date 2022-03-07
 */
@Service
public class LabTwoDimensionalCodeServiceImpl implements ILabTwoDimensionalCodeService {
    @Autowired
    private LabTwoDimensionalCodeMapper labTwoDimensionalCodeMapper;


    private static final String numberStr = "0123456789";

    private static final String uppercaseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final String lowercaseStr = "abcdefghijklmnopqrstuvwxyz";

    private static final String number = "数字(0-9)";

    private static final String uppercase = "大写字母(A_Z)";

    private static final String lowercase = "小写字母(a-z)";

    //随机生成密钥
    private static  byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();

    /**
     * 查询二维码
     *
     * @param id 二维码ID
     * @return 二维码
     */
    @Override
    public LabTwoDimensionalCode selectLabTwoDimensionalCodeById(Long id) {
        return labTwoDimensionalCodeMapper.selectLabTwoDimensionalCodeById(id);
    }

    /**
     * 查询二维码列表
     *
     * @param labTwoDimensionalCode 二维码
     * @return 二维码
     */
    @Override
    public List<LabTwoDimensionalCode> selectLabTwoDimensionalCodeList(LabTwoDimensionalCode labTwoDimensionalCode) {
        List<LabTwoDimensionalCode> labTwoDimensionalCodes = labTwoDimensionalCodeMapper.selectLabTwoDimensionalCodeList(labTwoDimensionalCode);
        //labTwoDimensionalCodes.stream().forEach(code -> code.setFilePath(preUrl + code.getId()));
        return labTwoDimensionalCodes;
    }

    /**
     * 新增二维码
     *
     * @param labTwoDimensionalCode 二维码
     * @return 结果
     */
    @Override
    public int insertLabTwoDimensionalCode(LabTwoDimensionalCode labTwoDimensionalCode) {
        ArrayList<String> list = getCodeStr(labTwoDimensionalCode);
        SysUser user = SecurityUtils.getLoginUser().getUser();
        ArrayList<LabTwoDimensionalCode> labTwoDimensionalCodes = new ArrayList<>();
        for (String s : list) {
            LabTwoDimensionalCode labTwoDimensionalCodeNew = new LabTwoDimensionalCode();
            String updatePath = encodeNoReturn(s, labTwoDimensionalCode.getColor());
            labTwoDimensionalCodeNew.setFilePath(updatePath);
            labTwoDimensionalCodeNew.setCode(s);
            labTwoDimensionalCodeNew.setColor(labTwoDimensionalCode.getColor());
            labTwoDimensionalCodeNew.setIsExport("0");
            labTwoDimensionalCodeNew.setIsBinding("0");
            labTwoDimensionalCodeNew.setCreatedTime(new Date());
            labTwoDimensionalCodeNew.setCreatedBy(user.getNickName());
            labTwoDimensionalCodes.add(labTwoDimensionalCodeNew);
        }
        return labTwoDimensionalCodeMapper.insertBatchLabTwoDimensionalCode(labTwoDimensionalCodes);
    }


    /**
     * 修改二维码
     *
     * @param labTwoDimensionalCode 二维码
     * @return 结果
     */
    @Override
    public int updateLabTwoDimensionalCode(LabTwoDimensionalCode labTwoDimensionalCode) {
        return labTwoDimensionalCodeMapper.updateLabTwoDimensionalCode(labTwoDimensionalCode);
    }

    /**
     * 批量删除二维码
     *
     * @param ids 需要删除的二维码ID
     * @return 结果
     */
    @Override
    public int deleteLabTwoDimensionalCodeByIds(Long[] ids) {
        for (Long id : ids) {
            deleteLabFile(id);
        }
        return labTwoDimensionalCodeMapper.deleteLabTwoDimensionalCodeByIds(ids);
    }

    /**
     * 删除二维码信息
     *
     * @param id 二维码ID
     * @return 结果
     */
    @Override
    public int deleteLabTwoDimensionalCodeById(Long id) {
        deleteLabFile(id);
        return labTwoDimensionalCodeMapper.deleteLabTwoDimensionalCodeById(id);
    }

    @Override
    public void updateLabTwoDimensionalCodeExprot(List<LabTwoDimensionalCode> list) {
        List<Long> collect = list.stream().map(LabTwoDimensionalCode::getId).collect(Collectors.toList());
        labTwoDimensionalCodeMapper.updateLabTwoDimensionalCodeExprot(collect);
    }
    
    public String getTwoDimensionalCode(String sourceCode){
    	 AES aes = SecureUtil.aes(key);
    	return Base64.encodeBase64String(aes.encrypt(sourceCode));
    }

    // 二维码生成字符编码
    private ArrayList<String> getCodeStr(LabTwoDimensionalCode labTwoDimensionalCode) {
        ArrayList<String> list = new ArrayList<>();
        String str = "";
        Integer codeNumber = labTwoDimensionalCode.getCodeNumber();
        //获取条码中间位置包含的内容
        String codeMiddleContent = labTwoDimensionalCode.getCodeMiddleContent();
        //获取条码结束位置包含的内容
        String codeEndContent = labTwoDimensionalCode.getCodeEndContent();
        //构建
        AES aes = SecureUtil.aes(key);
        DES des = SecureUtil.des(key);
        for (Integer i = 0; i < codeNumber; i++) {
            String codeStr = "";
            // 获取中间位字符
            String sortStringCodeMiddle = getString(labTwoDimensionalCode,codeMiddleContent);
            // 获取结束位字符
            String sortStringCodeEnd = getString(labTwoDimensionalCode,codeEndContent);
            str = labTwoDimensionalCode.getCodePre() + sortStringCodeMiddle + sortStringCodeEnd;
            // 进行加密处理
            if ("0".equals(labTwoDimensionalCode.getEncryptionType())){
                // Des加密
                 codeStr = Base64.encodeBase64String(des.encrypt(str));
            }else if ("1".equals(labTwoDimensionalCode.getEncryptionType())){
                //Aes加密
                 codeStr = Base64.encodeBase64String(aes.encrypt(str));
            }else {
                codeStr = str;
            }
            list.add(codeStr);
        }
        return list;
    }

    private String getString(LabTwoDimensionalCode labTwoDimensionalCode,String content) {
        StringBuilder sb = null;
        Random random = new Random();
        String sortString = "";
        if (content.contains(number) && !content.contains(uppercase) && !content.contains(lowercase)) {
            sb = new StringBuilder();
            // 只包含数字
            char[] chars = numberStr.toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else if (!content.contains(number) && content.contains(uppercase) && !content.contains(lowercase)) {
            sb = new StringBuilder();
            // 只包含大写字母
            char[] chars = (uppercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else if (!content.contains(number) && !content.contains(uppercase) && content.contains(lowercase)) {
            sb = new StringBuilder();
            // 只包含小写字母
            char[] chars = (lowercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else if (content.contains(number) && content.contains(uppercase) && !content.contains(lowercase)) {
            sb = new StringBuilder();
            // 包含数字和大写字母
            char[] chars = (numberStr + uppercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else if (content.contains(number) && !content.contains(uppercase) && content.contains(lowercase)) {
            sb = new StringBuilder();
            // 包含数字和小写字母
            char[] chars = (numberStr + lowercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else if (!content.contains(number) && content.contains(uppercase) && content.contains(lowercase)) {
            sb = new StringBuilder();
            // 包含大写和小写字母
            char[] chars = (uppercaseStr + lowercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        } else {
            sb = new StringBuilder();
            // 三个都包含
            char[] chars = (numberStr + uppercaseStr + lowercaseStr).toCharArray();
            for (int i = 0; i < 10; i++) {
                sb.append(chars[random.nextInt(chars.length)]);
            }
        }
        sortString = sb.toString();
        if (  null != labTwoDimensionalCode.getCodeEndRule() && labTwoDimensionalCode.getCodeEndRule().equals("1")) {
            sortString = sortChar(sortString);
        }
        return sortString;
    }

    private static String sortChar(String str) {
        // 1.将字符串转化成数组
        char[] chs = stringToArray(str);
        // 2.对数组进行排序
        sort(chs);
        // 3.将数组转成字符串
        return toString(chs);
    }

    private static String toString(char[] chs) {
        return new String(chs);
    }

    // 对字符数组进行升序排序
    private static void sort(char[] chs) {
        Arrays.sort(chs);
    }

    // 将字符串转化成为数组
    private static char[] stringToArray(String string) {
        return string.toCharArray();
    }
    public String encodeNoReturn(String content, String color) {
    	return this.encodeNoReturn(content, color, null);
    }

    public String encodeNoReturn(String content, String color, String basePath) {
        String uploadPath = "";
        try {
            // 二维码颜色(白色)
            int WHITE = 0xFFFFFFFF;
            int BLACK = 0xFF000000;
            if ("0".equals(color)) {
                // 红色
                BLACK = 0xFFFF0000;
            } else if ("1".equals(color)) {
                // 蓝色
                BLACK = 0xFF0000FF;
            }
            //定义二维码的参数
            @SuppressWarnings("rawtypes")
			HashMap<EncodeHintType, Comparable> hints = new HashMap<EncodeHintType, Comparable>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.MARGIN, 2);
            BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
            // 写出二维码图片到指定路径下
            //MatrixToImageWriter.writeToPath(matrix, "png", path);
            int width = matrix.getWidth();
            int height = matrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
                }
            }
            // 创建输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            // 将图像输出到输出流中。
            ImageIO.write(image, "jpeg", bos);
            MultipartFile multipartFile = new MockMultipartFile("test.jpeg", "test.png", "", bos.toByteArray());
            if(basePath==null){
            	 uploadPath = FileUploadUtils.upload(multipartFile);
            }else{
            	 uploadPath = FileUploadUtils.upload(basePath, multipartFile);
            }
           
        } catch (Exception e) {
            e.printStackTrace();
        }
        return uploadPath;
    }


    private void deleteLabFile(Long id) {
        LabTwoDimensionalCode labTwoDimensionalCode = new LabTwoDimensionalCode();
        labTwoDimensionalCode.setId(id);
        List<LabTwoDimensionalCode> labTwoDimensionalCodes = labTwoDimensionalCodeMapper.selectLabTwoDimensionalCodeList(labTwoDimensionalCode);
        if (labTwoDimensionalCodes != null && labTwoDimensionalCodes.size() > 0) {
            for (LabTwoDimensionalCode code : labTwoDimensionalCodes) {
               // System.out.println(RuoYiConfig.getProfile() + StringUtils.substringAfter(code.getFilePath(), Constants.RESOURCE_PREFIX));
                File file = new File(RuoYiConfig.getProfile() + StringUtils.substringAfter(code.getFilePath(), Constants.RESOURCE_PREFIX));
                file.deleteOnExit();
            }
        }
    }
}
